"""
Response formatting middleware
"""
import json
import time
from typing import Dict, Any
from fastapi import Request, Response
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware

class ResponseFormatterMiddleware(BaseHTTPMiddleware):
    """
    Middleware to format API responses with consistent structure
    """
    
    def __init__(self, app, format_responses: bool = True, add_metadata: bool = True):
        super().__init__(app)
        self.format_responses = format_responses
        self.add_metadata = add_metadata
    
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        
        # Only format JSON responses from API endpoints
        if (self.format_responses and 
            self._should_format_response(request, response)):
            return await self._format_response(request, response)
        
        return response
    
    def _should_format_response(self, request: Request, response: Response) -> bool:
        """Determine if response should be formatted"""
        # Don't format if not JSON
        content_type = response.headers.get("content-type", "")
        if "application/json" not in content_type:
            return False
        
        # Don't format streaming responses
        if response.status_code == 200 and "text/event-stream" in content_type:
            return False
        
        # Don't format if already formatted (has error or data structure)
        if hasattr(response, '_formatted'):
            return False
        
        # Format API endpoints but skip documentation endpoints
        path = request.url.path
        skip_paths = ["/docs", "/redoc", "/openapi.json"]
        if any(path.startswith(skip) for skip in skip_paths):
            return False
        
        return True
    
    async def _format_response(self, request: Request, response: Response) -> Response:
        """Format the response with consistent structure"""
        try:
            # For streaming responses, don't format
            if hasattr(response, 'body_iterator'):
                # Get response body
                body = b""
                async for chunk in response.body_iterator:
                    body += chunk
                
                # Parse existing JSON response
                if body:
                    try:
                        original_data = json.loads(body.decode())
                    except (json.JSONDecodeError, UnicodeDecodeError):
                        # If not JSON, return original response
                        return response
                else:
                    original_data = None
                
                # Check if it's already a formatted response
                if (isinstance(original_data, dict) and
                    ("error" in original_data or "success" in original_data)):
                    # Already formatted response (error or StandardResponse)
                    formatted_data = original_data

                    # Still add metadata if enabled and not already present
                    if self.add_metadata and "metadata" not in formatted_data:
                        formatted_data["metadata"] = {
                            "timestamp": time.time(),
                            "path": request.url.path,
                            "method": request.method,
                            "process_time": response.headers.get("X-Process-Time")
                        }
                else:
                    # Format raw response
                    formatted_data = {
                        "success": response.status_code < 400,
                        "data": original_data,
                        "status_code": response.status_code
                    }

                    # Add metadata if enabled
                    if self.add_metadata:
                        formatted_data["metadata"] = {
                            "timestamp": time.time(),
                            "path": request.url.path,
                            "method": request.method,
                            "process_time": response.headers.get("X-Process-Time")
                        }
                
                # Create new formatted response without copying old headers that might cause conflicts
                new_headers = {}
                for key, value in response.headers.items():
                    # Skip content-length as it will be recalculated
                    if key.lower() not in ["content-length"]:
                        new_headers[key] = value
                
                new_response = JSONResponse(
                    content=formatted_data,
                    status_code=response.status_code,
                    headers=new_headers
                )
                
                # Mark as formatted to avoid double processing
                new_response._formatted = True
                
                return new_response
            else:
                return response
            
        except Exception as e:
            # If formatting fails, return original response
            return response


def response_formatter_middleware(format_responses: bool = True, add_metadata: bool = True):
    """Factory function to create response formatter middleware"""
    def create_middleware(app):
        return ResponseFormatterMiddleware(app, format_responses=format_responses, add_metadata=add_metadata)
    return create_middleware


# Helper functions for creating standardized responses
def create_success_response(data: Any = None, message: str = "操作成功") -> Dict[str, Any]:
    """
    Create a standardized success response

    Args:
        data: Response data
        message: Success message

    Returns:
        Dictionary with standardized success response format
    """
    return {
        "success": True,
        "message": message,
        "data": data
    }


def create_error_response(message: str = "操作失败", status_code: int = 400, detail: Any = None) -> JSONResponse:
    """
    Create a standardized error response

    Args:
        message: Error message
        status_code: HTTP status code
        detail: Additional error details

    Returns:
        JSONResponse with standardized error format
    """
    content = {
        "success": False,
        "message": message
    }
    if detail:
        content["data"] = {"detail": detail}

    return JSONResponse(
        status_code=status_code,
        content=content
    )